package com.jacky.crypto;

import androidx.annotation.NonNull;

import java.io.File;
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;

import io.flutter.embedding.engine.plugins.FlutterPlugin;
import io.flutter.plugin.common.MethodCall;
import io.flutter.plugin.common.MethodChannel;
import io.flutter.plugin.common.MethodChannel.MethodCallHandler;
import io.flutter.plugin.common.MethodChannel.Result;
import io.flutter.plugin.common.PluginRegistry;

/** CryptoPlugin */
public class CryptoPlugin implements FlutterPlugin, MethodCallHandler {

  public static void registerWith(PluginRegistry.Registrar registrar) {
    final MethodChannel channel = new MethodChannel(registrar.messenger(), "com.jacky.util/crypto");
    channel.setMethodCallHandler(new CryptoPlugin());
  }

  /// The MethodChannel that will the communication between Flutter and native Android
  ///
  /// This local reference serves to register the plugin with the Flutter Engine and unregister it
  /// when the Flutter Engine is detached from the Activity
  private MethodChannel channel;
  private ExecutorService service;

  @Override
  public void onAttachedToEngine(@NonNull FlutterPluginBinding flutterPluginBinding) {
    channel = new MethodChannel(flutterPluginBinding.getBinaryMessenger(), "com.jacky.util/crypto");
    channel.setMethodCallHandler(this);
    service = Executors.newCachedThreadPool();
  }

  @Override
  public void onMethodCall(@NonNull MethodCall call, @NonNull Result result) {
    String method = call.method;

    switch (method) {
      case "md5String": {
        String content = (String) call.arguments;
        result.success(EDA.MD5.digest(content));
        break;
      }
      case "md5File": {
        String path = (String) call.arguments;
        service.execute(new FileRunnable(path, result, true));
        break;
      }
      case "md5Byte":
        byte[] data = (byte[]) call.arguments;
        result.success(EDA.MD5.digest(data));
        break;
      case "sha256String": {
        String content = (String) call.arguments;
        result.success(EDA.SHA256.digest(content));
        break;
      }
      case "sha256File": {
        String path = (String) call.arguments;
        service.execute(new FileRunnable(path, result, false));
        break;
      }
      case "aesEncrypt": {
        String content = call.argument("content");
        String password = call.argument("password");
        Boolean hex = call.argument("hex");
        result.success(EDA.AES.encrypt(content, password, hex));
        break;
      }
      case "aesDecrypt": {
        String content = call.argument("content");
        String password = call.argument("password");
        Boolean hex = call.argument("hex");
        result.success(EDA.AES.decrypt(content, password, hex));
        break;
      }
      case "macsha256": {
        String content = call.argument("content");
        String password = call.argument("password");
        Boolean hex = call.argument("hex");
        result.success(EDA.SHA256.sha256_mac(content, password, hex));
        break;
      }
      case "rsaEncrypt": {
        String content = call.argument("content");
        String password = call.argument("key");
        Boolean hex = call.argument("hex");
        result.success(EDA.RSA.encrypt(content, password, hex));
        break;
      }
      case "rsaDecrypt": {
        String content = call.argument("content");
        String password = call.argument("key");
        Boolean hex = call.argument("hex");
        result.success(EDA.RSA.decrypt(content, password, hex));
        break;
      }
      default:
        //result.notImplemented();
        break;
    }
  }

  @Override
  public void onDetachedFromEngine(@NonNull FlutterPluginBinding binding) {
    channel.setMethodCallHandler(null);
    service.shutdown();
  }

  //文件需要开线程计算
  private static class FileRunnable implements Runnable {

    FileRunnable(String path, Result result, boolean md5) {
      this.result = result;
      this.path = path;
      this.md5 = md5;
    }

    String path;
    Result result;
    boolean md5;

    @Override
    public void run() {
      if(md5) {
        result.success(EDA.MD5.digest(new File(path)));
      } else {
        result.success(EDA.SHA256.digest(new File(path)));
      }
    }
  }
}
